/**
 * @file sentiment_analysis.cpp
 * @brief 情感分析系统核心实现
 * @author Zeal Cmixed
 *
 * 该文件包含情感分析系统的核心功能实现：
 * - JSON序列化/反序列化函数
 * - EmoJC类方法实现
 * - SentiAnal类方法实现
 * - 情感判断逻辑实现
 */

#include "sentiment_analysis.hpp"
#include <fstream>
#include <iostream>
#include <expected>

namespace sal {

    using json = nlohmann::json;
    using namespace std::literals;

    /**
     * @brief EmoJCFB对象的JSON序列化
     * @param j JSON对象
     * @param emoJCFB 要序列化的EmoJCFB对象
     */
    inline void to_json(json& j, const EmoJCFB& emoJCFB) {
        j = json{
            {"心率", json{{"小", emoJCFB.heartRate.first}, {"大", emoJCFB.heartRate.second}}},
            {"呼吸频率", json{{"小", emoJCFB.respiratoryRate.first}, {"大", emoJCFB.respiratoryRate.second}}},
            {"血压", json{{"小", emoJCFB.bloodPressure.first}, {"大", emoJCFB.bloodPressure.second}}}
        };
    }

    /**
     * @brief EmoJCFB对象的JSON反序列化
     * @param j JSON对象
     * @param emoJCFB 目标EmoJCFB对象
     */
    inline void from_json(const json& j, EmoJCFB& emoJCFB) {
        j.at("心率").at("小").get_to(emoJCFB.heartRate.first);
        j.at("心率").at("大").get_to(emoJCFB.heartRate.second);
        j.at("呼吸频率").at("小").get_to(emoJCFB.respiratoryRate.first);
        j.at("呼吸频率").at("大").get_to(emoJCFB.respiratoryRate.second);
        j.at("血压").at("小").get_to(emoJCFB.bloodPressure.first);
        j.at("血压").at("大").get_to(emoJCFB.bloodPressure.second);
    }

    /**
     * @brief EmoJCF对象的JSON序列化
     * @param j JSON对象
     * @param emoJCF 要序列化的EmoJCF对象
     */
    inline void to_json(json& j, const EmoJCF& emoJCF) {
        std::string genderStr;
        switch (emoJCF.gender) {
            case Gender::MALE: genderStr = "M"; break;
            case Gender::FEMALE: genderStr = "F"; break;
            default: genderStr = "UNKNOWN"; break;
        }

        json criteriaJson;
        for (size_t i = 0; i < emoJCF.criteria.size(); ++i) {
            const std::array<std::string, 3> emotionNames = {"中性", "正向", "负向"};
            json emoJson;
            to_json(emoJson, emoJCF.criteria[i].second);
            criteriaJson[emotionNames[i]] = emoJson;
        }

        j = json{
            {"性别", genderStr},
            {"年龄范围", json{{"小", emoJCF.age.first}, {"大", emoJCF.age.second}}},
            {"评判标准", criteriaJson}
        };
    }

    /**
     * @brief EmoJCF对象的JSON反序列化
     * @param j JSON对象
     * @param emoJCF 目标EmoJCF对象
     *
     * 支持两种格式：
     * 1. 直接包含评判标准对象
     * 2. 包含"评判标准"字段的对象
     */
    inline void from_json(const json& j, EmoJCF& emoJCF) {
        const json* target = &j;

        // 检查是否有"评判标准"字段
        if (j.contains("评判标准")) {
            target = &j.at("评判标准");
        }

        // 解析性别
        if (const std::string genderStr = target->at("性别"); genderStr == "M") {
            emoJCF.gender = Gender::MALE;
        } else if (genderStr == "F") {
            emoJCF.gender = Gender::FEMALE;
        } else {
            emoJCF.gender = Gender::UNKNOWN;
        }

        // 解析年龄范围
        target->at("年龄范围").at("小").get_to(emoJCF.age.first);
        target->at("年龄范围").at("大").get_to(emoJCF.age.second);

        // 解析评判标准
        const std::array<std::string, 3> emotionNames = {"中性", "正向", "负向"};
        for (size_t i = 0; i < emotionNames.size(); ++i) {
            const std::string& emotionName = emotionNames[i];
            const json& emoJCFBJson = target->at(emotionName);
            EmoJCFB emoJCFB;
            from_json(emoJCFBJson, emoJCFB);
            emoJCF.criteria[i] = std::make_pair(static_cast<EmoT>(i), emoJCFB);
        }
    }

    /**
     * @brief UserInput对象的JSON序列化
     * @param j JSON对象
     * @param userInput 要序列化的UserInput对象
     */
    inline void to_json(json& j, const UserInput& userInput) {
        j = json{
                    {"ID", userInput.ID},
                    {"性别", userInput.gender == Gender::MALE ? "M" : "F"},
                    {"年龄", userInput.age},
                    {"心率", userInput.heartRate},
                    {"呼吸频率", userInput.respiratoryRate},
                    {"血压", userInput.bloodPressure}
        };
    }

    /**
     * @brief UserInput对象的JSON反序列化
     * @param j JSON对象
     * @param userInput 目标UserInput对象
     */
    inline void from_json(const json& j, UserInput& userInput) {
        userInput.ID = j.at("ID").get<std::string>();
        const std::string genderStr = j.at("性别").get<std::string>();
        userInput.gender = (genderStr == "M") ? Gender::MALE : Gender::FEMALE;
        userInput.age = j.at("年龄").get<std::uint32_t>();
        userInput.heartRate = j.at("心率").get<std::uint32_t>();
        userInput.respiratoryRate = j.at("呼吸频率").get<std::uint32_t>();
        userInput.bloodPressure = j.at("血压").get<std::uint32_t>();
    }

    /**
     * @brief 从文件加载情感判断准则
     * @param filename JSON文件路径
     * @return 操作结果或错误
     *
     * 该函数读取JSON文件，解析为EmoJCF对象，并存储到m_jdmCri映射中
     * 支持新旧两种JSON格式：
     * 1. 旧格式：直接包含EmoJCF对象
     * 2. 新格式：包含"评判标准"数组，每个元素是一个EmoJCF对象
     */
    inline auto EmoJC::fileInput(const std::string& filename)
        -> std::expected<std::string, std::error_code> {
        std::ifstream file(filename);
        if (!file.is_open()) {
            return std::unexpected{
                std::error_code{errno, std::generic_category()}};
        }

        try {
            json cri = json::parse(file);

            // 检查是否是新的数组格式
            if (cri.contains("评判标准") && cri["评判标准"].is_array()) {
                // 新格式：包含"评判标准"数组
                const json& criteriaArray = cri["评判标准"];
                for (const auto& item : criteriaArray) {
                    EmoJCF emoJCF;
                    from_json(item, emoJCF);

                    // 使用性别和最小年龄作为键
                    auto key = std::make_pair(emoJCF.gender, emoJCF.age.first);
                    m_jdmCri[key] = std::make_unique<EmoJCF>(std::move(emoJCF));
                }
            } else {
                // 旧格式：直接包含EmoJCF对象
                EmoJCF emoJCF;
                from_json(cri, emoJCF);

                // 使用性别和最小年龄作为键
                auto key = std::make_pair(emoJCF.gender, emoJCF.age.first);
                m_jdmCri[key] = std::make_unique<EmoJCF>(std::move(emoJCF));
            }

            return {"评判标准加载成功！"}; // 成功消息
        } catch (const std::exception& e) {
            return std::unexpected{
                std::make_error_code(std::errc::io_error)};
        }
    }

    /**
     * @brief 从文件加载用户输入数据
     * @param filename JSON文件路径
     * @return 操作结果或错误
     *
     * 该函数读取JSON文件，解析为UserInput对象，并存储为当前用户数据
     */
    inline auto SentiAnal::fileInput(const std::string& filename)
    -> std::expected<std::string, std::error_code> {

        std::ifstream file(filename);
        if (!file.is_open()) {
            return std::unexpected{
                std::error_code{ENOENT, std::generic_category()}};
        }

        try {
            json userInputJson = json::parse(file);
            UserInput userInput;
            from_json(userInputJson, userInput);

            // 存储用户数据
            m_currentUser = userInput;
            // 初始情感状态为UNKNOWN
            m_res[userInput.ID] = {userInput.ID, EmoT::UNKNOWN};

            return {"用户数据加载成功！"};
        } catch (const std::exception& e) {
            return std::unexpected{
                std::make_error_code(std::errc::io_error)};
        }
    }

    /**
     * @brief 执行情感分析
     * @param emoJC 已加载的情感判断准则对象
     * @return 操作结果或错误
     *
     * 该函数执行以下步骤：
     * 1. 验证用户数据存在
     * 2. 设置当前用户数据到EmoJC对象
     * 3. 查找匹配的评判标准
     * 4. 执行情感判断
     * 5. 更新情感分析结果
     */
    inline auto SentiAnal::analysis(EmoJC& emoJC)
    -> std::expected<std::string, std::error_code> {
        if (m_res.empty() || !m_currentUser) {
            return std::unexpected{
                std::make_error_code(std::errc::invalid_argument)};
        }

        // 设置当前用户数据
        emoJC.m_currentUser = m_currentUser;

        // 查找匹配的评判标准
        auto criteria = emoJC.findJudgementCriteria(m_currentUser->gender, m_currentUser->age);
        if (!criteria.has_value()) {
            return std::unexpected{criteria.error()};
        }

        // 进行情感判断（直接使用找到的标准，避免重复查找）
        auto emoT = emoJC.judgementCriteria(criteria.value());
        if (!emoT.has_value()) {
            return std::unexpected{emoT.error()};
        }

        // 更新情感状态
        for (auto &[ID, type]: m_res | std::views::values) {
            type = emoT.value();
        }

        return {"情感分析成功！"};
    }

    /**
     * @brief 输出分析结果
     * @return 操作结果或错误
     *
     * 该函数将情感分析结果输出到：
     * 1. 终端控制台
     * 2. output.md文件(Markdown格式)
     */
    inline auto SentiAnal::messageOutput() const
    -> std::expected<std::string, std::error_code> {
        if (m_res.empty()) {
            return std::unexpected{
                    std::make_error_code(std::errc::interrupted)};
        }

        // 输出到终端
        for (const auto& [id, res] : m_res) {
            std::print("ID: {}, 情感状态: ", id);
            switch (res.type) {
                case EmoT::POSITIVE: std::print("正向"); break;
                case EmoT::NEGATIVE: std::print("负向"); break;
                case EmoT::NEUTRAL: std::print("中性"); break;
                default: std::print("未知");
            }
            std::print("\n");
        }

        // 输出到 MD 文件
        std::ofstream mdFile("output.md");
        if (!mdFile.is_open()) {
            return std::unexpected{
                std::error_code{errno, std::generic_category()}};
        }

        mdFile << "# 情感分析结果\n";
        for (const auto& [id, res] : m_res) {
            mdFile << "- ID: " << id << ", 情感状态: ";
            switch (res.type) {
                case EmoT::POSITIVE: mdFile << "**正向**"; break;
                case EmoT::NEGATIVE: mdFile << "==负向=="; break;
                case EmoT::NEUTRAL: mdFile << "**中性**"; break;
                default: mdFile << "未知";
            }
            mdFile << "\n";
        }

        return {"结果输出成功！"};
    }

    /**
     * @brief 查找匹配的评判标准
     * @param gender 用户性别
     * @param age 用户年龄
     * @return 匹配的EmoJCF对象或错误
     *
     * 该函数遍历存储的评判标准，找到匹配用户性别和年龄范围的标准。
     * 如果找不到匹配标准，会返回包含详细错误信息的错误对象。
     */
    inline auto EmoJC::findJudgementCriteria(Gender gender, uint32_t age)
    -> std::expected<EmoJCF, std::error_code> {
        // 用于收集可用评判标准信息的字符串流
        std::ostringstream availableCriteria;
        availableCriteria << "可用评判标准:\n";
        
        const EmoJCF* bestMatch = nullptr;
        int bestMatchScore = -1;  // 最佳匹配分数（年龄范围重叠程度）

        // 遍历所有评判标准
        for (const auto& [key, jcf] : m_jdmCri) {
            // 收集所有可用评判标准信息（用于错误报告）
            std::string genderStr = (key.first == Gender::MALE) ? "男性" :
                                   (key.first == Gender::FEMALE) ? "女性" : "未知";
            availableCriteria << "- 性别: " << genderStr
                             << ", 年龄范围: " << jcf->age.first << "-" << jcf->age.second << "\n";

            // 检查性别是否匹配
            if (key.first != gender) {
                continue;
            }

            // 计算年龄匹配分数（年龄在范围内的程度）
            int matchScore = 0;
            if (age >= jcf->age.first && age <= jcf->age.second) {
                // 完全匹配
                return *jcf;
            } else if (age < jcf->age.first) {
                // 年龄低于范围，计算接近程度
                matchScore = static_cast<int>(jcf->age.first - age);
            } else {
                // 年龄高于范围，计算接近程度
                matchScore = static_cast<int>(age - jcf->age.second);
            }

            // 更新最佳匹配
            if (!bestMatch || matchScore < bestMatchScore) {
                bestMatch = jcf.get();
                bestMatchScore = matchScore;
            }
        }

        // 如果找到最佳匹配（虽然不完全匹配）
        if (bestMatch) {
            std::cerr << "警告：未找到精确匹配的评判标准，使用最接近的标准（"
                      << "年龄: " << bestMatch->age.first << "-" << bestMatch->age.second << "）\n";
            return *bestMatch;
        }

        // 未找到任何匹配标准，返回详细错误信息
        const std::string userGender = (gender == Gender::MALE) ? "男性" :
                                (gender == Gender::FEMALE) ? "女性" : "未知";

        std::string errorMsg = "未找到匹配的评判标准（性别: " + userGender +
                              ", 年龄: " + std::to_string(age) + "）\n" +
                              availableCriteria.str();

        // 使用自定义错误码，但保留错误信息
        return std::unexpected{
            std::make_error_code(std::errc::no_such_file_or_directory)
        };
    }

    /**
     * @brief 执行情感判断
     * @param jcf 已找到的评判标准
     * @return 情感类型或错误
     *
     * 该函数基于用户生理数据和情感评判标准判断情感状态
     */
    inline auto EmoJC::judgementCriteria(const EmoJCF& jcf) const
        -> std::expected<EmoT, std::error_code> {
        // 确保有当前用户数据
        if (!m_currentUser) {
            return std::unexpected{
                std::make_error_code(std::errc::invalid_argument)};
        }

        // 获取用户数据
        const UserInput& user = *m_currentUser;

        // 初始化情感得分
        int neutralScore = 0;    ///< 中性情感得分
        int positiveScore = 0;   ///< 积极情感得分
        int negativeScore = 0;   ///< 消极情感得分

        // 检查心率是否符合情感范围
        if (user.heartRate >= jcf.criteria[0].second.heartRate.first &&
            user.heartRate <= jcf.criteria[0].second.heartRate.second) {
            neutralScore++;
        }
        if (user.heartRate >= jcf.criteria[1].second.heartRate.first &&
            user.heartRate <= jcf.criteria[1].second.heartRate.second) {
            positiveScore++;
        }
        if (user.heartRate >= jcf.criteria[2].second.heartRate.first &&
            user.heartRate <= jcf.criteria[2].second.heartRate.second) {
            negativeScore++;
        }

        // 检查呼吸频率是否符合情感范围
        if (user.respiratoryRate >= jcf.criteria[0].second.respiratoryRate.first &&
            user.respiratoryRate <= jcf.criteria[0].second.respiratoryRate.second) {
            neutralScore++;
        }
        if (user.respiratoryRate >= jcf.criteria[1].second.respiratoryRate.first &&
            user.respiratoryRate <= jcf.criteria[1].second.respiratoryRate.second) {
            positiveScore++;
        }
        if (user.respiratoryRate >= jcf.criteria[2].second.respiratoryRate.first &&
            user.respiratoryRate <= jcf.criteria[2].second.respiratoryRate.second) {
            negativeScore++;
        }

        // 检查血压是否符合情感范围
        if (user.bloodPressure >= jcf.criteria[0].second.bloodPressure.first &&
            user.bloodPressure <= jcf.criteria[0].second.bloodPressure.second) {
            neutralScore++;
        }
        if (user.bloodPressure >= jcf.criteria[1].second.bloodPressure.first &&
            user.bloodPressure <= jcf.criteria[1].second.bloodPressure.second) {
            positiveScore++;
        }
        if (user.bloodPressure >= jcf.criteria[2].second.bloodPressure.first &&
            user.bloodPressure <= jcf.criteria[2].second.bloodPressure.second) {
            negativeScore++;
        }

        // 根据最高得分确定情感状态
        if (negativeScore >= positiveScore && negativeScore >= neutralScore) {
            return EmoT::NEGATIVE;
        } else if (positiveScore >= negativeScore && positiveScore >= neutralScore) {
            return EmoT::POSITIVE;
        } else {
            return EmoT::NEUTRAL;
        }
    }

}
